﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nature.Toolkit.GMix;

namespace Nature.Data
{
    public class AH2004ModelObject : ModelObject
    {
        internal readonly System.Collections.IEnumerable Entities;

        public AH2004ModelObject(ModelSetupInfo setupInfo, params Uri[] webResource)
        {
            IContractsHeap contractsHeap = new CkDataBag(webResource);
            Entities = contractsHeap.ToEntitiesHeap(setupInfo ?? new ModelSetupInfo());
            InitEntitySets();
            base.Initialize();
            ApplySettings(setupInfo);
        }

        public AH2004ModelObject(System.Collections.IEnumerable entities)
        {
            Entities = entities.Cast<object>().ToArray();
            InitEntitySets();
            base.Initialize();
        }


        public AH2004ModelObject GetReducedModel(ModelFilters filters)
        {
            return new AH2004ModelObject(filters.ReduceEntitiesSet(this.Entities));
        }

        private void ApplySettings(ModelFilters filter)
        {
            if (filter.TabulateIdealGasThermodynamicPotentials)
            {
                base.TabulateIdealGasThermodynamicPotentials(10d, 10000d, 0.05);
            }
        }

        private void InitEntitySets()
        {
            this.Species = Entities.OfType<ChemicalSpecies>().OrderBy(sp=> sp.Ordinal).ToArray();
            this.Elements = Entities.OfType<ChemicalElement>().ToArray();
            this.Thermo7 = this.Species.Select(sp=> sp.Thermo7).ToArray();
            this.GasKinParameters = this.Species.Select(sp=> sp.GasKinParameters).ToArray();
            this.Reactions = Entities.OfType<ChemicalReaction>().OrderBy(i=> i.Ordinal).ToArray();
        }

        public ReadOnlyArray<ChemicalElement> Elements { get; private set; }
        public ReadOnlyArray<ChemicalSpecies> Species { get; private set; }
        public ReadOnlyArray<ChemicalReaction> Reactions { get; private set; }
        public ReadOnlyArray<Thermo7> Thermo7 { get; private set; }
        public ReadOnlyArray<GasKinParameters> GasKinParameters { get; private set; }        


        protected override string[] GetElementIDs()
        {
            return Elements.Select(i => i.ElementID).ToArray();
        }

        protected override string[] GetSpeciesIDs()
        {
            return Species.Select(i => i.SpeciesID).ToArray();
        }

        protected override double[] GetElementMolarMasses()
        {
            return Elements.Select(i => i.ElementMolarMass).ToArray();
        }

        protected override double[] GetSpeciesMolarMasses()
        {
            return Species.Select(i => i.SpeciesMolarMass).ToArray();
        }

        protected override double[][] GetSpelMatrix()
        {
            double[][] spel = new double[Species.Length][];
            for (int isp = 0; isp < spel.Length; ++isp)
            {
                spel[isp] = new double[Elements.Length];
                var sp = Species[isp];
                for (int iel = 0; iel < Elements.Length; ++iel)
                {
                    var el = Elements[iel];
                    var apm = el.AtomsPerMoleculeAmounts.Where(i => i.SpeciesID == sp.SpeciesID)
                        .Select(i => i.AtomsPerMolecule)
                        .SingleOrDefault();
                    spel[isp][iel] = apm;
                }
            }
            return spel;
        }

        protected override IIdealGasSpeciesThermoPotentials GetIIdealGasSpeciesThermoPotentials()
        {
            return new Thermo7IdealGasSpeciesThermoPotentials(this.Thermo7,
                GetSpeciesMolarMasses());
        }

        protected override IIdealGasSpeciesMolecularTransportProperties GetIdealGasSpeciesMolecularTransportProperties()
        {
            return new AH2004IdealGasSpeciesMolecularTransportProperties(this);
        }

        protected override IIdealGasMixtureMolecularTransportProperties GetIdealGasMixtureMolecularTransportProperties()
        {
            return new WilkeIdealGasMixtureMolecularTransportProperties();
        }

        protected override IChemicalEquilibriumCalculator GetIdealGasChemicalEquilibriumCalculator()
        {
            return new Nature.Toolkit.GEqu.IdealGasChemicalEquilibriumCalculator(this);
        }

        protected override IChemicalKinetics GetIdealGasChemicalKinetics()
        {
            if (Nre > 0)
            {
                var schema = new ChemicalKineticsRuntimeTextTemplateSchema(this);
                return schema.ToChemicalKineticsObject();
            }
            return new ChemicalKineticsNullObject(Nsp);
        }

        public override IEnumerable<IMixtureDefinition> ParseMixtureDefinition(string mixtureDefinition)
        {
            mixtureDefinition = AdaptMixtureDefinition(mixtureDefinition);
            Nature.Toolkit.GMix.IExpression expression =
                Nature.Data.GMixMarkup.GMixExpression.Parse(mixtureDefinition);
            var projections = new Nature.Toolkit.GMix.MixProjectionCollection(
                expression, Entities, new MixSetupInfo()
                {
                    DefaultPressure = new Pressure(1.0, PressureUnits.Atmosphere),
                    DefaultTemperature = new Temperature(300.0, TemperatureUnits.Kelvin)
                });
            return
                from projection in projections
                let rootComposition = projection.CompositionObjects.Where(i => i.Component.IsRoot).Single()
                select rootComposition;
        }

        protected override string[] GetReactionIDs()
        {
            return 
                (
                    from r in Reactions
                    select r.ToString()
                ).ToArray();
        }
    }
}
